package com.salmon.test;


import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.testkit.javadsl.TestKit;
import com.salmon.study.iot.Device;
import com.salmon.study.iot.ReadTemperature;
import com.salmon.study.iot.RecordTemperature;
import com.salmon.study.iot.RespondTemperature;
import com.salmon.study.iot.TemperatureRecorded;
import com.salmon.study.iot.group.DeviceGroup;
import com.salmon.study.iot.group.message.DeviceRegistered;
import com.salmon.study.iot.group.message.ReplyDeviceList;
import com.salmon.study.iot.group.message.RequestDeviceList;
import com.salmon.study.iot.group.message.RequestTrackDevice;
import org.junit.Test;

import java.time.Clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.Assert.assertEquals;

public class IoTTester {

    @Test
    public void testReplyWithEmptyReadingIfNoTemperatureIsKnown() {
        ActorSystem system = ActorSystem.create();
        TestKit probe = new TestKit(system);
        ActorRef deviceActor = system.actorOf(Device.props("group", "device"));
        deviceActor.tell(new ReadTemperature(42L), probe.getRef());
        RespondTemperature response = probe.expectMsgClass(RespondTemperature.class);
        assertEquals(42L, response.getRequestId());
        assertEquals(Optional.empty(), response.getValue());

        system.terminate();
    }

    @Test
    public void testReplyWithLatestTemperatureReading() {
        ActorSystem system = ActorSystem.create();
        TestKit probe = new TestKit(system);
        //设置温度为24
        ActorRef deviceActor = system.actorOf(Device.props("group", "device"));
        //发送  温度设置为 24
        deviceActor.tell(new RecordTemperature(1L, 24.0), probe.getRef());
        assertEquals(1L, probe.expectMsgClass(TemperatureRecorded.class).getRequestId());
        // 查询温度
        deviceActor.tell(new ReadTemperature(2L), probe.getRef());
        RespondTemperature response = probe.expectMsgClass(RespondTemperature.class);
        assertEquals(2L, response.getRequestId());
        assertEquals(Optional.of(24.0), response.getValue());

        //把温度设为55
        deviceActor.tell(new RecordTemperature(3L, 55.0), probe.getRef());
        assertEquals(3L, probe.expectMsgClass(TemperatureRecorded.class).getRequestId());

        deviceActor.tell(new ReadTemperature(4L), probe.getRef());
        RespondTemperature response2 = probe.expectMsgClass(RespondTemperature.class);
        assertEquals(4L, response2.getRequestId());
        assertEquals(Optional.of(55.0), response2.getValue());

        system.terminate();
    }


    @Test
    public void testIgnoreWrongRegisterRequests() {
        ActorSystem system = ActorSystem.create();
        TestKit probe = new TestKit(system);
        ActorRef deviceActor = system.actorOf(Device.props("group", "device"));
        deviceActor.tell(new RequestTrackDevice("workgroup", "device"), probe.getRef());
        probe.expectNoMessage();
        deviceActor.tell(new RequestTrackDevice("group", "device"), probe.getRef());
        //probe.expectNoMessage();
        probe.expectMsgClass(DeviceRegistered.class);


        system.terminate();
    }


    /**
     * 系统中如果已有一个Device Actor，则不再创建Device Actor：
     */
    @Test
    public void testReturnSameActorForSameDeviceId() {
        ActorSystem system = ActorSystem.create();
        TestKit probe = new TestKit(system);
        ActorRef groupActor = system.actorOf(DeviceGroup.props("group"));

        groupActor.tell(new RequestTrackDevice("group", "device1"),
                probe.getRef());
        probe.expectMsgClass(DeviceRegistered.class);//收到了确认消息
        ActorRef deviceActor1 = probe.getLastSender();//刚刚创建的Actor

        groupActor.tell(new RequestTrackDevice("group", "device1"),
                probe.getRef());
        probe.expectMsgClass(DeviceRegistered.class);
        ActorRef deviceActor2 = probe.getLastSender();
        assertEquals(deviceActor1, deviceActor2);//断言没有创建新Actor，返回的是上次创建的Actor
    }

    @Test
    public void testListActiveDevices() {
        ActorSystem system = ActorSystem.create();
        TestKit probe = new TestKit(system);
        ActorRef groupActor = system.actorOf(DeviceGroup.props("group"));

        groupActor.tell(new RequestTrackDevice("group", "device1"),probe.getRef());
        probe.expectMsgClass(DeviceRegistered.class);

        groupActor.tell(new RequestTrackDevice("group", "device2"),probe.getRef());
        probe.expectMsgClass(DeviceRegistered.class);

        groupActor.tell(new RequestDeviceList(0L), probe.getRef());
        ReplyDeviceList reply = probe.expectMsgClass(ReplyDeviceList.class);
        assertEquals(0L, reply.getRequestId());
        assertEquals(Stream.of("device1", "device2").collect(Collectors.toSet()),
                reply.getIds());

        system.terminate();
    }

    @Test
    public void testTime() {
        long ts = System.currentTimeMillis();
        //Instant now = Instant.now(); // UTS 时间
        Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8)); // 东八区时间
        System.out.println(now);
        LocalDateTime now1 = LocalDateTime.now(); // 这个是北京时间  本地时间
        System.out.println(now1);
        Instant instant = Instant.ofEpochMilli(ts);// 这个是UTS 时间 ， 不是北京时间 在格式化的时候 指定了 时区withZone，才能正确格式化
        System.out.println(instant);
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
        System.out.println(fmt.format(instant));
    }
}
